//typescript语法学习
/*
ts就是类型安全的js，对比对应的js代码就是添加了类型声明
 */
let a:number //声明变量a是number
a=123
//a="123" 这里是不允许的！
let b=123 //ts可以自动根据变量的值推断出变量的类型
//这种方式最少用，显示声明类型禀赋值
let c:number=456 
//如果一个变量类型不确定，可以用any,此时退化成js
let d:any //默认也是any
d=465
d="hello"
//数组类型，在ts中可以用类型[]或者是Array<类型名>进行类型声明
let e :string[] //e是一个string数组
e=["1","2"]
let f:Array<string>
f=["3","4"]
//any会出现这种倾向
f=d //f是一个字符串数组，d是any但是d可以赋值给f
//类型安全的any --->unknown,
let g:unknown
// f=g 这种情况是错误的，unknown不可以赋值给确定类型的变量
//函数类型的声明
let i:(a:number,b:number)=>number 
i=(a:number,b:number):number =>{
    return a+b
}
//元组，ts新加入的对应类型，本质是长度固定的数组
let j:[string,number]
j=["123",23]
//这杨会报错 j=["123",23,140]
//枚举类型，使用enum关键字声明，类似于C语言中的enum用法
enum SexType{
    Male, //默认是0，可以自定义
    Female,
}
//联合类型的语法声明
/* let k:"111"|123 |[456] 
k="111"
k=123
k=[456]
变量的赋值只能固定选择对应的联合类型的值，使用不灵活，使用更多的是下面这种方式
let k:string |number 1 //k的类型是string或者number都可以
 */
/*
对象类型的声明语法： 
*/
/* let m:object  */
//使用字面值的时候，这种方式更加常见,
let m:{name:string,age:number ,[propName:string]:any}
m={name:"chy",age:18,x:1,y:"123",z:[1,2,3]}
//类型别名，类似于c语言中的typedef关键字，对类型进行重新声明，具体语法如下
type myType=string | number 
let n:myType;
n=123
n="123" //string或是number都是可以
/*
类型断言：语法格式 变量名 as 类型名 | <类型名>变量 
e as string ->标识e只能是string
<string>e ->标识e也是string
*/
/*
接口的语法书写 
*/
interface MyInterface{
    //可以只写属性名和类型，接口中的所有部分都不能有值，因为必须重写
    name:string,
    age:number,
    //也可以是函数，建议不要用箭头，因为未来很可能需要重写
    sayHello():number  //方法不能写实现
}
//...下面可能是实现了接口的方法
class MyImpl implements MyInterface{
    name:string
    age:number
    constructor(name:string,age:number){
        this.name=name
        this.age=age
    }
    sayHello(): number {
        console.log("大家好")
        return this.age
    }
}
/*
泛型的书写，对于函数和类，ts支持使用泛型 
函数返回值不写，默认返回void
函数还有返回值never，这个就是什么都不返回
void可以接受null,undefine这些值
*/
//返回一个元组
function Turtle<T>(a:T,b:T): [x:T,y:T]{
    return [a,b]    
}
//可以让ts自动推断参数，也可以显示推断参数(1,2)，或者显示传递类型参数
Turtle(1,2)
Turtle<number>(1,2)
//test函数的泛型参数必须是实现了MyInterface的类
function test<T extends MyInterface>(a:T):T{
    return a
}
//这样调用即可，泛型也可以添加到类型参数上，都可以
test<MyImpl>(new MyImpl('chy',18))
//可以使用typeof运算符作为反省参数
test<typeof string>("hello");